﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using BEPUphysics;
using Microsoft.Xna.Framework;
using PloobsEngine.Physics;
using PloobsEngine.SceneControl;

namespace PloobsEngine.Physic.PhysicObjects.BepuObject
{
    public class TerrainObject : IPhysicObject    
    {
        String image;
        Terrain terrain;
        float xSpacing = 8f;
        float ySpacing = 8f;
        float heightMultipler = 10f;
        float maxHeight = float.MaxValue;

        public float MaxHeight
        {
            get { return maxHeight; }
            set { maxHeight = value; }
        }
        float minHeight = float.MinValue;

        public float MinHeight
        {
            get { return minHeight; }
            set { minHeight = value; }
        }

        public Terrain Terrain
        {
            get { return terrain; }
            set { terrain = value; }
        }

        public TerrainObject(String heighmapName)                    
             : this(heighmapName,8,8,10)
        {            
        }

        /// <summary>
        /// Create a Terrain Physic Object
        /// </summary>
        /// <param name="heighmapName">Name of the heighmap texture</param>
        /// <param name="xSpacing">Default 8</param>
        /// <param name="ySpacing">Default 8 </param>
        /// <param name="heightMultipler">Default 10 - controla a altura, menor mais alto </param>
        public TerrainObject(String heighmapName, float xSpacing, float ySpacing, float heightMultipler)
        {
            this.xSpacing = xSpacing;
            this.ySpacing = ySpacing;
            this.heightMultipler = heightMultipler;
            this.image = heighmapName;                        
            
            Texture2D sourceImage = EngineStuff.CustomContentManager.GetAsset<Texture2D>(image);
            int xLength = sourceImage.Width;
            int yLength = sourceImage.Height;

            Color[] colorData = new Color[xLength * yLength];
            sourceImage.GetData<Color>(colorData);            

            var heights = new float[xLength, yLength];
            for (int i = 0; i < xLength; i++)
            {
                for (int j = 0; j < yLength; j++)
                {
                    Color color = colorData[j * xLength + i];
                    //Adding together the RGB channels has no particular meaning- it's just to create some difference in height.
                    //This could be done using non-Color textures, too.  For example, a grayscale image would just have one value to directly use.
                    heights[i, j] = (color.R + color.G + color.B) / heightMultipler;

                    if (heights[i, j] > maxHeight)
                    {
                        maxHeight = heights[i, j];
                    }
                    if (heights[i, j] < minHeight)
                    {
                        minHeight = heights[i, j];
                    }

                }
            }
            //Create the terrain.
            terrain = new Terrain(new Vector3(-xLength * xSpacing / 2, 0, -yLength * ySpacing / 2));            
            terrain.SetData(heights, QuadFormats.LowerLeftUpperRight, xSpacing, ySpacing);                                    
            
            terrain.UseFaceNormalWithinAngle = (float)Math.PI / 2; //This terrain shape is very flat, so the triangle normals can be safely used in every case.
            //Generally, it is fine to use the triangle normals, but if the terrain has extremely sharp cliffs and features you may notice
            //some 'stickiness' or other more severe problems.  Triangles can be set to use the normal contact normals always by setting the terrain.tryToUseTriangleNormals to false.
            //The benefit of using the triangles' normals is smoother behavior for sliding objects at the boundary between triangles.
                        
        }

        #region IPhysicObject Members

        public Vector3 Position
        {
            get
            {
                return terrain.GetPosition();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public Vector3 Scale
        {
            get
            {
                return Vector3.One;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public Matrix Rotation
        {
            get
            {
                return Matrix.Identity;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public Vector3 FaceVector
        {
            get { throw new NotImplementedException(); }
        }

        public Matrix WorldMatrix
        {
            get { return Matrix.CreateTranslation(Position); }
        }

        public Vector3 Velocity
        {
            get
            {
                return Vector3.Zero;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public void Serialize(System.Xml.XmlTextWriter textWriter)
        {            
        }

        public void DeSerialize(System.Xml.XmlNode node, EngineStuff engine, PloobsEngine.Modelo.IModelo model, Vector3 position, Matrix rotation)
        {         
        }

        public bool isMotionLess
        {
            get
            {
                return true;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        IObject owner;
        public IObject ObjectOwner
        {
            get
            {
                return owner;
            }
            set
            {
                this.owner = value;
            }
        }

        public PhysicObjectTypes PhysicObjectTypes
        {
            get { return PhysicObjectTypes.TERRAIN; }
        }

        public void Enable()
        {
            throw new NotImplementedException();
        }

        public void Disable()
        {
            throw new NotImplementedException();
        }

        public void ApplyImpulse(Vector3 force)
        {
            throw new NotImplementedException();
        }

        public void ApplyTorque(Vector3 force)
        {
            throw new NotImplementedException();
        }

        public BoundingBox BoundingBox
        {
            get { return terrain.BoundingBox; }
        }

        #endregion
    }
}
